/*
 *  include/clinux/sched.h
 *
 *  last modified at 2007.07.15 00:33 by ChenJie
 *
 */

#ifndef SCHED_H
#define SCHED_H

#include <cos/config.h>
#include <cos/kernel.h>
#include <cos/ipc.h>

#define NR_PRIORITY	16

//进程运行可能处的状态：
#define TASK_RUNNING		1		//正在运行，或就绪
#define TASK_INTERRUPTIBLE	2		//
#define TASK_UNINTERRUPTIBLE	3		//任务等待IO操作
#define TASK_ZOMBIE		4		//
#define TASK_STOPPED		5		//任务已停止

//进程运行初始时间片：
#define TASK_INIT_COUNTER	15

//进程优先级：
#define TASK_KERNEL_PRIORITY	5

#define TASK0_TSS_ENTRY		4
#define TASK0_LDT_ENTRY		(TASK0_TSS_ENTRY+1)

/*
 * 任务n的TSS段描述符在GDT中的表项
 */
#define TASK_TSS_ENTRY(n)	((n)*2 + TASK0_TSS_ENTRY)
/*
 * 任务n的LDT段描述符在GDT中的表项
 */
#define TASK_LDT_ENTRY(n)	((n)*2 + TASK0_LDT_ENTRY)
/*
 * 任务n的TSS选择子
 */
#define TASK_TSS_SELECTOR(n)	(TASK_TSS_ENTRY(n)<<3)
/*
 * 任务n的LDT选择子
 */
#define TASK_LDT_SELECTOR(n)	(TASK_LDT_ENTRY(n)<<3)

struct ldt_struct {
	struct desc_struct	kstack;		// kernel stack descriptor 
	struct desc_struct	ucode;		// user code descriptor 
	struct desc_struct	udata;		// user data descriptor 
	struct desc_struct	ustack;		// user stack descriptor 
};

//i387结构:
struct i387_struct {
	unsigned long	cwd;		//控制字(Control word)
	unsigned long	swd;		//状态字(Status word)
	unsigned long	twd;
	unsigned long	fip;
	unsigned long	fcs;
	unsigned long	foo;
	unsigned long	fos;
	unsigned long	st_space[20];
};

//TSS结构：
struct tss_struct {
	unsigned long	back_link;	//高字为0
	unsigned long	esp0;
	unsigned long	ss0;		//高定为0
	unsigned long	esp1;
	unsigned long	ss1;		//高字为0
	unsigned long	esp2;
	unsigned long	ss2;		//高字为0
	unsigned long	cr3;
	unsigned long	eip;
	unsigned long	eflags;
	unsigned long	eax;
	unsigned long 	ecx;
	unsigned long 	edx;
	unsigned long	ebx;
	unsigned long	esp;
	unsigned long	ebp;
	unsigned long	esi;
	unsigned long	edi;
	unsigned long	es;		//高字为0
	unsigned long	cs;		//高字为0
	unsigned long	ss;		//高字为0
	unsigned long	ds;		//高字为0
	unsigned long	fs;		//高字为0
	unsigned long	gs;		//高字为0
	unsigned long	ldt;		//高字为0
	unsigned long	trace_bitmap;	
};
	
struct proc_struct {
	struct proc_struct *next;
	
	long task_nr;
	long status;
	long priority;
	long counter;
	unsigned long utime;
	unsigned long ktime;
	
	struct ldt_struct	ldt;

	struct tss_struct 	tss;

	struct i387_struct i387;

	long	pid;	
	
	unsigned long ulevel;
	unsigned long start_time; 

	unsigned long reenter;              // 0 is user-mode, >0 is kernel-mode

	struct msgbox_struct msgbox;	
	//the sleeping process  has been ready for receiving msg.
	struct proc_struct *	waiting_for_sending; 
	//the sleeping process has been ready for sending msg.	
	struct proc_struct *	waiting_for_receiving;	
	//the sleeping process has been ready for receiveing any msg.
	struct proc_struct *	waiting_for_any_arrive;  

	unsigned long kstack;
 };



struct context_struct {
	unsigned long	gs;
	unsigned long	fs;
	unsigned long	es;
	unsigned long	ds;
	unsigned long	ebp;
	unsigned long	esi;
	unsigned long	edi;
	unsigned long	edx;
	unsigned long	ecx;
	unsigned long	ebx;
	unsigned long	eax;
	unsigned long	eip;
	unsigned long	cs;
	unsigned long	eflags;
	unsigned long	esp;
	unsigned long	ss;
};
struct kernel_stack_struct {
	unsigned long	sapce[1008];
	struct context_struct ucontext;
};
union proc_union {
	struct proc_struct proc;	//task
	struct kernel_stack_struct kstack; //kernel_stack
};

struct procs_struct {
	struct proc_struct * task[NR_TASKS];
	struct proc_struct * ready_head[NR_PRIORITY];
	struct proc_struct * ready_tail[NR_PRIORITY];
	struct proc_struct * running_proc;
	struct proc_struct * last_proc_used_math;
	unsigned long jiffies;
	long last_pid;
};

extern struct procs_struct procs;


extern void begin_schedule(void);
extern void schedule(void);
extern void sched_init(void);
extern long enqueue(struct proc_struct * proc_ptr);
extern long dequeue(struct proc_struct * proc_ptr);
extern struct proc_struct * get_proc_ptr(long pid);
extern long is_sleeping_on(long pid, struct proc_struct ** event);
extern void sleep_on(struct proc_struct ** event);
extern long wake_up(long pid, struct proc_struct ** event);


/*
 * 功能:
 * 	切换到任务 n
 * 输入:
 * 	n	目标任务的标识号
 * 输出:
 * 	无
 * 全局变量:
 * 	task
 * 	current_task
 * 处理说明:
 * 	1.切换时机是在ring0级, 切换后原任务tss动态字段内容是ring0的上下文.
 * 	  但目标任务初次被切换运行时, 其动态字段的初始内容是fork系统调用时的
 * 	  ring3 的上下文.
 * 	2.任务切换前要指定current_task为目标任务.
 * 	3.切换出的目标任务的运行状态分两种情况:
 * 		(1)目标任务的tss动态字段是由fork设定.此时返回点在fork调用的下
 * 		   一条指令, 运行级为ring3.
 * 		(2)目标任务的tss动态字段是因任务切换自动更新.此时返回点在
 * 		   task_switch_to函数的任务切换的下一指令, 运行级为ring0.
 */
static inline void proc_switch_to(struct proc_struct *next_proc)
{
	unsigned long new_task_addr[2];
	if(next_proc==procs.running_proc)
		return;
	procs.running_proc = next_proc;
	new_task_addr[1] = TASK_TSS_SELECTOR(next_proc->task_nr);
	__asm__("ljmp *%0"::"m"(*new_task_addr));
}



#endif // SCHED_H
